package com.zhm.checker

import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.CompilationUnit
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
import com.github.javaparser.ast.body.FieldDeclaration
import com.github.javaparser.ast.body.MethodDeclaration
import com.github.javaparser.ast.body.Parameter
import com.github.javaparser.ast.stmt.BlockStmt
import com.github.javaparser.ast.type.Type
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.TaskAction

import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

class ApiAnnotationCheckerPlugin implements Plugin<Project> {
    @Override
    void apply(Project project) {
        project.extensions.create("apiAnnotationChecker", ApiAnnotationCheckerExtension)
        def myTask = project.tasks.create("checkApiAnnotations", ApiAnnotationCheckerTask)
        project.tasks.named('build').configure {
            dependsOn(myTask)
        }
    }
}

class ApiAnnotationCheckerExtension {
    String sourcePath = "src/main/java"
    String apiAnnotationClassName = "com.zhm.base.TestApi"
}

class ApiAnnotationCheckerTask extends DefaultTask {
    @TaskAction
    void checkAnnotations() {
        println System.getProperty("user.dir")
        def extension = project.extensions.getByType(ApiAnnotationCheckerExtension)
        Path sourceDir = Paths.get(extension.sourcePath)
        Files.walk(sourceDir)
                .filter { Files.isRegularFile(it) && it.toString().endsWith(".java") }
                .forEach { processJavaFile(it, extension.apiAnnotationClassName) }
    }

    static void processJavaFile(Path filePath, String apiAnnotationClassName) {
        String content = new String(Files.readAllBytes(filePath))
        CompilationUnit cu = StaticJavaParser.parse(content)

        cu.findAll(ClassOrInterfaceDeclaration.class).forEach { classDecl ->
            classDecl.findAll(FieldDeclaration.class).forEach { fieldDecl ->
                fieldDecl.getAnnotations().stream()
                        .filter {it.getNameAsString() == apiAnnotationClassName}
                        .findFirst()
                        .ifPresent { annotation ->
                            fieldDecl.getVariables().forEach { variable ->
                                Type fieldType = variable.getType()
                                if (!fieldType.asString().startsWith("String")) {
                                    addSetMethod(classDecl, variable.getNameAsString(), fieldType)
                                }
                            }
                        }
            }
        }


        String res = cu.toString();
        Files.write(filePath, res.getBytes("UTF-8"))
    }

    static void addSetMethod(ClassOrInterfaceDeclaration classDecl, String fieldName, Type fieldType) {
        String methodName = "set${fieldName.capitalize()}"
        if (!classDecl.getMethodsByName(methodName).isEmpty()) {
            return
        }

        MethodDeclaration method = new MethodDeclaration()
                .setName(methodName)
                .setType("void")
                .addParameter(new Parameter(fieldType, "value"))
                .setBody(new BlockStmt()
                        .addStatement("this.${fieldName} = value;"))

        classDecl.addMember(method)
    }

    static void main(String[] args) {
        processJavaFile(Paths.get("D:\\javaWorkSpace\\boot3-test\\demo\\src\\main\\java\\com\\zhm\\demo\\a\\TestBean.java"), "TestApi")

//        Path path = Paths.get("D:\\a.txt")
//        try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
//            writer.write("asdfasfdasfasfas")
//        } catch (Exception e) {
//            e.printStackTrace()
//        }
    }
}
